// Tierless
// Copyright © 2010 Alphora
// This file is licensed under a modified BSD-license (see tierless_license.txt).
using System;
using System.Runtime.Serialization;

namespace Tierless.Framework.Constraints.Common
{
	/// <summary>
	/// Ensures that a date time value is within a restricted range of values supported on most data platforms.
	/// </summary>
	[DataContract]
	public class DateTimeInRange : ColumnConstraint
	{
		/// <summary>
		/// The minimum supported date value.
		/// </summary>
		public static readonly DateTime MinDate = new DateTime(1900, 1, 1);

		/// <summary>
		/// The maximum supported date value.
		/// </summary>
		public static readonly DateTime MaxDate = new DateTime(2999, 12, 31);

		/// <summary>
		/// Constructs a new instance of a DateTimeInRange constraint.
		/// </summary>
		/// <param name="entityTypeName">The name of the entity type on which the constraint will be placed.</param>
		/// <param name="columnName">The name of the column on which the constraint will be placed.</param>
		public DateTimeInRange(string entityTypeName, string columnName)
			: base
			(
				String.Format("{0}_{1}DateTimeInRange", entityTypeName, columnName),
				entityTypeName,
				columnName,
				String.Format("Datetime value must be between {0} and {1}.", MinDate.ToShortDateString(), MaxDate.ToShortDateString())
			)
		{}

		protected override bool IsValid(ConstraintContext context)
		{
			var tempValue = context.EntityChange.Entity[ColumnName].Value;
			if (tempValue is DateTime?)
			{
				var nullableValue = (DateTime?) tempValue;
				return DateInRange(nullableValue);
			}

			if (tempValue != null)
			{
				var dateTime = (DateTime) tempValue;
				return DateInRange(dateTime);
			}

			return true;
		}

		/// <summary>
		/// Returns true if the given date time value is in the supported range of date time values.
		/// </summary>
		/// <param name="date">The date to be tested.</param>
		/// <returns>True if the date is within the supported range of date time values, false otherwise.</returns>
		public static bool DateInRange(DateTime? date)
		{
			return !date.HasValue || ((date.Value >= MinDate) && (date.Value <= MaxDate));
		}
	}
}